﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AmiEmuLib
{
    public static class MemoryHelpers
    {
        #region Allign
        public static bool IsLongAllign(uint a_value)
        {
            return (a_value % 4) == 0;
        }

        public static bool IsWordAllign(uint a_value)
        {
            return (a_value % 2) == 0;
        }

        public static bool IsBankAllign(uint a_value)
        {
            return (a_value % Consts.BANK_SIZE) == 0;
        }
        #endregion

        #region Long, Word, Bytes manipulation
        public static byte GetLowByte(uint a_uint)
        {
            return (byte)a_uint;
        }

        public static void SetLowByte(ref uint a_uint, byte a_low)
        {
            a_uint = (a_uint & (uint)0xFFFFFF00) | a_low;
        }

        public static ushort GetLowWord(uint a_uint)
        {
            return (ushort)a_uint;
        }

        public static void SetLowWord(ref uint a_uint, ushort a_low)
        {
            a_uint = (a_uint & (uint)0xFFFF0000) | a_low;
        }

        public static uint SetLowWord(uint a_uint, ushort a_low)
        {
            return (a_uint & (uint)0xFFFF0000) | a_low;
        }

        public static ushort GetHighWord(uint a_uint)
        {
            return (ushort)(a_uint >> 16);
        }

        public static void SetHighWord(ref uint a_uint, ushort a_high)
        {
            a_uint = (a_uint & (uint)0x0000FFFF) | ((uint)a_high << 16);
        }

        public static uint SetHighWord(uint a_uint, ushort a_high)
        {
            return (a_uint & (uint)0x0000FFFF) | ((uint)a_high << 16);
        }

        public static byte GetLowByte(ushort a_ushort)
        {
            return (byte)a_ushort;
        }

        public static void SetLowByte(ref ushort a_ushort, byte a_low)
        {
            a_ushort = (ushort)((a_ushort & 0xFF00) | a_low);
        }

        public static ushort SetLowByte(ushort a_ushort, byte a_low)
        {
            return (ushort)((a_ushort & 0xFF00) | a_low);
        }

        public static byte GetHighByte(ushort a_ushort)
        {
            return (byte)(a_ushort >> 8);
        }

        public static void SetHighByte(ref ushort a_ushort, byte a_low)
        {
            a_ushort = (ushort)((a_ushort & (uint)0x000000FF) | ((uint)a_low << 8));
        }

        public static ushort SetHighByte(ushort a_ushort, byte a_low)
        {
            return (ushort)((a_ushort & (uint)0x000000FF) | ((uint)a_low << 8));
        }

        public static uint MakeLong(byte a_high, byte a_b1, byte a_b2, byte a_low)
        {
            return (uint)((uint)a_high << 24) | ((uint)a_b1 << 16) | ((uint)a_b2 << 8) | a_low;
        }

        public static uint MakeLong(ushort a_high, ushort a_low)
        {
            return (uint)(a_high << 16) | a_low;
        }

        public static ushort MakeWord(byte a_high, byte a_low)
        {
            return (ushort)((a_high << 8) | a_low);
        }
        #endregion

        #region Hex support
        private static byte[] m_trans_hex_to_bin = new byte[255];
        private static char[] m_trans_bin_to_hex = new [] { '0', '1', '2', '3', '4', '5', '6', '7', 
                                                            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

        static MemoryHelpers()
        {
            for (int i='0'; i<='9'; i++)
                m_trans_hex_to_bin[i] = (byte)(i - '0');
            for (int i = 'a'; i <= 'f'; i++)
                m_trans_hex_to_bin[i] = (byte)(i - 'a' + 10);
            for (int i = 'A'; i <= 'F'; i++)
                m_trans_hex_to_bin[i] = (byte)(i - 'A' + 10);
        }

      

        public static ushort[] HexToAmigaMemory(string a_str)
        {
            ushort[] result = new ushort[a_str.Length / 4];
            HexToAmigaMemory(a_str, result, 0);
            return result;
        }

        public static void HexToAmigaMemory(string a_str, ushort[] a_array, uint a_index)
        {
            for (int i = 0; i < a_str.Length / 4; i++)
            {
                a_array[a_index + i] = (ushort)(
                    (m_trans_hex_to_bin[a_str[i * 4]] << 12) |
                    (m_trans_hex_to_bin[a_str[i * 4 + 1]] << 8) |
                    (m_trans_hex_to_bin[a_str[i * 4 + 2]] << 4) |
                    m_trans_hex_to_bin[a_str[i * 4 + 3]]);
            }
        }

        public static string AmigaMemoryToHex(ushort[] a_array)
        {
            return AmigaMemoryToHex(a_array, 0, (uint)a_array.Length);
        }

        public static string AmigaMemoryToHex(ushort[] a_array, uint a_index, uint a_size)
        {
            StringBuilder str = new StringBuilder((int)(a_size * 4));
            str.Length = (int)(a_size * 4);

            for (int i = 0; i < a_size; i++)
            {
                ushort word = a_array[i + a_index];
                str[i * 4] = m_trans_bin_to_hex[word >> 12];
                str[i * 4 + 1] = m_trans_bin_to_hex[(word >> 8) & 0x0F];
                str[i * 4 + 2] = m_trans_bin_to_hex[(word >> 4) & 0x0F];
                str[i * 4 + 3] = m_trans_bin_to_hex[word & 0x0F];
            }

            return str.ToString();
        }
        #endregion
    }
}
